package cn.tlb.utils;

import java.util.ArrayList;

/**
 * Created by 汤林冰 on 2015/12/16 10:23.
 */
public class AverageNormal{
    private static final String TAG = "AverageNormal";
    //顶点
    private final float vertices[]= {
            0, -0.525731f, 0.850651f,             // vertices[0]
            0.850651f, 0, 0.525731f,              // vertices[1]
            0.850651f, 0, -0.525731f,             // vertices[2]
            -0.850651f, 0, -0.525731f,            // vertices[3]
            -0.850651f, 0, 0.525731f,             // vertices[4]
            -0.525731f, 0.850651f, 0,             // vertices[5]
            0.525731f, 0.850651f, 0,              // vertices[6]
            0.525731f, -0.850651f, 0,             // vertices[7]
            -0.525731f, -0.850651f, 0,            // vertices[8]
            0, -0.525731f, -0.850651f,            // vertices[9]
            0, 0.525731f, -0.850651f,             // vertices[10]
            0, 0.525731f, 0.850651f               // vertices[11]
    };

    // 面索引
    private final int indices[] = {
            1, 2, 6,
            1, 7, 2,
            3, 4, 5,
            4, 3, 8,
            6, 5, 11,
            5, 6, 10,
            9, 10, 2,
            10, 9, 3,
            7, 8, 9,
            8, 7, 0,
            11, 0, 1,
            0, 11, 4,
            6, 2, 10,
            1, 6, 11,
            3, 5, 10,
            5, 4, 11,
            2, 7, 9,
            7, 1, 0,
            3, 9, 8,
            4, 8, 0
    };


    int[][] faceArray = arrays(indices, 3);

    float[][] faceNormals = new float[indices.length/3][3];
    {
        //计算每个面的法向量
        for (int i = 0; i < indices.length; i+=3) {
            // 得到顶点索引
            int a = indices[i   ];
            int b = indices[i + 1];
            int c = indices[i + 2];
            // 得到每个顶点坐标
            float[] p1 = {vertices[a], vertices[a+1], vertices[a+2]};
            float[] p2 = {vertices[b], vertices[b+1], vertices[b+2]};
            float[] p3 = {vertices[c], vertices[c+1], vertices[c+2]};
            // 计算法向量
            //                 i            j           k
            float[] v1 = {p1[0]-p2[0], p1[1]-p2[1], p1[2]-p2[2]};
            float[] v2 = {p1[0]-p3[0], p1[1]-p3[1], p1[2]-p3[2]};
            // 计算v1 v2交叉积
            float[] normal = {v1[1]*v2[2]-v1[2]*v2[1], -(v1[0]*v2[2]-v1[2]*v2[0]), v1[0]*v2[1]-v1[1]*v2[0]};
            // 单位化  由于三角形绘制的顺序问题,没办法统一得到外(内)法向
            float length = (float) Math.sqrt(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]);
            for (int j = 0; j < normal.length; j++) {
                normal[j] /= length;
            }
            faceNormals[i] = normal;
        }
    }

    float[][] avgVertexNormal = new float[vertices.length/3][3];
    {
        for (int y = 0; y < avgVertexNormal.length; y++) {
            ArrayList<float[]> floats = new ArrayList<>();
            //遍历每个顶点
            for (int i = 0; i < vertices.length / 3; i++) {
                // 取出所有包含该顶点的面
                for (int j = 0; j < faceArray.length; j++) {
                    for (int k = 0; k <faceArray[j].length ; k++) {
                        if(i == faceArray[j][k]){
                            floats.add(faceNormals[j]);
                        }
                    }
                }
            }
            //计算平均向量
            float[] v = new float[3];
            for (int i = 0; i < floats.size() ; i++) {
                for (int j = 0; j < v.length; j++) {
                    v[i] += floats.get(i)[j];
                }
            }
            for (int i = 0; i < v.length; i++) {
                v[i] /= floats.size();
            }
            avgVertexNormal[y] = v;
        }
    }

    private float[][] arrays(float[] array, int size){
        if(array.length%size != 0){
            throw new IllegalArgumentException("array.length % size != 0");
        }
        float[][] floats = new float[array.length/size][size];
        for (int i = 0; i < floats.length; i++) {
            for (int j = 0; j < size; j++) {
                floats[i][j] = array[size*i+j];
            }
        }
        return floats;
    }

    private int[][] arrays(int[] array, int size){
        if(array.length%size != 0){
            throw new IllegalArgumentException("array.length % size != 0");
        }
        int[][] floats = new int[array.length/size][size];
        for (int i = 0; i < floats.length; i++) {
            for (int j = 0; j < size; j++) {
                floats[i][j] = array[size*i+j];
            }
        }
        return floats;
    }
}
